/*
Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/

This file is part of PircBot.

This software is dual-licensed, allowing you to choose between the GNU
General Public License (GPL) and the www.jibble.org Commercial License.
Since the GPL may be too restrictive for use in a proprietary application,
a commercial license is also provided. Full license information can be
found at http://www.jibble.org/licenses/

 */
package org.jibble.pircbot;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

/**
 * This class is used to process DCC events from the server.
 * 
 * @since 1.2.0
 * @author Paul James Mutton, <a href="http://www.jibble.org/">http://www.jibble.org/</a>
 * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007)
 */
public class DccManager {

   private final PircBot _bot;

   private final List<DccFileTransfer> _awaitingResume = new ArrayList<DccFileTransfer>();

   /**
    * Constructs a DccManager to look after all DCC SEND and CHAT events.
    * 
    * @param bot
    *           The PircBot whose DCC events this class will handle.
    */
   DccManager(final PircBot bot) {
	  _bot = bot;
   }

   /**
    * Add this DccFileTransfer to the list of those awaiting possible resuming.
    * 
    * @param transfer
    *           the DccFileTransfer that may be resumed.
    */
   protected void addAwaitingResume(final DccFileTransfer transfer) {
	  synchronized (_awaitingResume) {
		 _awaitingResume.add(transfer);
	  }
   }

   /**
    * Processes a DCC request.
    * 
    * @return True if the type of request was handled successfully.
    */
   protected boolean processRequest(final String nick, final String login, final String hostname, final String request) {
	  final StringTokenizer tokenizer = new StringTokenizer(request);
	  tokenizer.nextToken();
	  final String type = tokenizer.nextToken();
	  final String filename = tokenizer.nextToken();

	  if (type.equals("SEND")) {
		 final long address = Long.parseLong(tokenizer.nextToken());
		 final int port = Integer.parseInt(tokenizer.nextToken());
		 long size = -1;
		 try {
			size = Long.parseLong(tokenizer.nextToken());
		 } catch (final Exception e) {
			// Stick with the old value.
		 }

		 final DccFileTransfer transfer = new DccFileTransfer(_bot, this, nick, login, hostname, type, filename, address, port,
			   size);
		 _bot.onIncomingFileTransfer(transfer);

	  } else if (type.equals("RESUME")) {
		 final int port = Integer.parseInt(tokenizer.nextToken());
		 final long progress = Long.parseLong(tokenizer.nextToken());

		 DccFileTransfer transfer = null;
		 synchronized (_awaitingResume) {
			for (int i = 0; i < _awaitingResume.size(); i++) {
			   transfer = _awaitingResume.get(i);
			   if (transfer.getNick().equals(nick) && transfer.getPort() == port) {
				  _awaitingResume.remove(i);
				  break;
			   }
			}
		 }

		 if (transfer != null) {
			transfer.setProgress(progress);
			_bot.sendCTCPCommand(nick, "DCC ACCEPT file.ext " + port + " " + progress);
		 }

	  } else if (type.equals("ACCEPT")) {
		 final int port = Integer.parseInt(tokenizer.nextToken());
		 // long progress = Long.parseLong(tokenizer.nextToken());

		 DccFileTransfer transfer = null;
		 synchronized (_awaitingResume) {
			for (int i = 0; i < _awaitingResume.size(); i++) {
			   transfer = _awaitingResume.get(i);
			   if (transfer.getNick().equals(nick) && transfer.getPort() == port) {
				  _awaitingResume.remove(i);
				  break;
			   }
			}
		 }

		 if (transfer != null) {
			transfer.doReceive(transfer.getFile(), true);
		 }

	  } else if (type.equals("CHAT")) {
		 final long address = Long.parseLong(tokenizer.nextToken());
		 final int port = Integer.parseInt(tokenizer.nextToken());

		 final DccChat chat = new DccChat(_bot, nick, login, hostname, address, port);

		 new Thread() {

			@Override
			public void run() {
			   _bot.onIncomingChatRequest(chat);
			}
		 }.start();
	  } else
		 return false;

	  return true;
   }

   /**
    * Remove this transfer from the list of those awaiting resuming.
    */
   protected void removeAwaitingResume(final DccFileTransfer transfer) {
	  _awaitingResume.remove(transfer);
   }

}
